package chapter10;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class MyClassLoader extends ClassLoader{
    private final static Path  DEFAULT_CLASS_DIR = Paths.get("F:", "classLoaderDir1");

    private final Path classDir;
    public MyClassLoader(){
        super();
        this.classDir = DEFAULT_CLASS_DIR;
    }
    public MyClassLoader(String classDir) {
        super();
        this.classDir = Paths.get(classDir);
    }

    public MyClassLoader(ClassLoader parent) {
        super(parent);
        this.classDir = DEFAULT_CLASS_DIR;
    }
    public MyClassLoader(ClassLoader parent, String classDir) {
        super(parent);
        this.classDir = Paths.get(classDir);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classBytes = this.readClassBytes(name);
        if (null == classBytes || classBytes.length == 0){
            throw new ClassNotFoundException("Can not load the class "+ name);
        }
        //调用defineClass方法定义class
        /**
         * name定义类的名字
         * classBytes class文件的二进制字节数组
         * off 字节数组的偏移量
         * classBytes.length 从偏移量开始读取多长的byte数据
         */
        return this.defineClass(name, classBytes, 0, classBytes.length);
    }

    private byte[] readClassBytes(String name) throws ClassNotFoundException {
        //包分隔符转换为文件分隔符
        String classPath = name.replace(".","/");
        Path classFullPath = classDir.resolve(Paths.get(classPath + ".class"));
        if (!classFullPath.toFile().exists()){
            throw new ClassNotFoundException("the class " + name +" not found.");
        }
        //将class文件读取到内存中
        try (ByteArrayOutputStream bao = new ByteArrayOutputStream()){
            Files.copy(classFullPath, bao);
            return bao.toByteArray();
        } catch (IOException e) {
            throw new ClassNotFoundException("load the class "+ name +" occur error.", e );
        }
    }

    @Override
    public String toString() {
        return "My Class Loader.";
    }
}
